home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / util / gnu / oleo_src.lha / src / cell.c < prev    next >
C/C++ Source or Header  |  1992-08-18  |  29KB  |  1,287 lines

  1. /*    Copyright (C) 1990 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 1, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "funcdef.h"
  20.  
  21. #include <stdio.h>
  22.  
  23. #define obstack_chunk_alloc ck_malloc
  24. #define obstack_chunk_free free
  25. #include "obstack.h"
  26.  
  27. #include "sysdef.h"
  28.  
  29. #include "global.h"
  30. #include "cell.h"
  31.  
  32. /* How many rows/columns to allocate to either side of an allocated cell */
  33. #ifdef __TURBOC__
  34. #define ROW_BUFF    0
  35. #define COL_BUFF    0
  36. #else
  37. #define ROW_BUFF    4
  38. #define COL_BUFF    2
  39. #endif
  40.  
  41. #ifdef REVERSE
  42. #define MIN_R MIN_COL
  43. #define MAX_R MAX_COL
  44. #define MIN_C MIN_ROW
  45. #define MAX_C MAX_ROW
  46. #else
  47. #define MIN_R MIN_ROW
  48. #define MAX_R MAX_ROW
  49. #define MIN_C MIN_COL
  50. #define MAX_C MAX_COL
  51. #endif
  52.  
  53. extern void byte_free EXT1(unsigned char *);
  54. extern void flush_variables EXT0();
  55.  
  56. typedef struct col COL;
  57. typedef struct row ROW;
  58.  
  59. /* Cells are stored in a two-dimentional sparse array.  This allows us to have
  60.    a fair-sized namespace (255x255 or 65535x65535) without using incredible
  61.    amounts of memory.  (64Kx64K cells would use up 120GIG of memory just for
  62.    the cell structures. . .)
  63.  
  64.    Note that the sparse arrays are not currently garbage collected, although
  65.    flush_everything will free all the row and column structures, as well
  66.    as everything in them. . .
  67.  */
  68. struct row {
  69.     ROW *row_next;
  70.     CELLREF    row_low;
  71.     CELLREF    row_high;
  72.     COL *cols[1];
  73. };
  74.  
  75. static ROW *the_rows;
  76.  
  77. struct col {
  78.     struct col *col_next;
  79.     CELLREF    col_low;
  80.     CELLREF    col_high;
  81.     CELL cells[1];
  82. };
  83.  
  84. static ROW *make_row_at EXT3(CELLREF, ROW *, ROW **);
  85. static ROW *row_alloc EXT3N(CELLREF, CELLREF, ROW *);
  86.  
  87. static void out_of_date EXT0();
  88.  
  89. static COL *col_alloc EXT3N(CELLREF, CELLREF, COL *);
  90.  
  91. extern CELL *my_cell;
  92. extern CELLREF cur_row,cur_col;
  93.  
  94. #define row_free(x)    out_of_date(),free(x)
  95. #define col_free(x)    \
  96.     do{\
  97.         out_of_date();\
  98.         if(   my_cell \
  99.             && my_cell>= &(x->cells[0]) \
  100.             && my_cell<=&(x->cells[x->col_high-x->col_low])) \
  101.                my_cell=find_cell(cur_row,cur_col); \
  102.         free(x); \
  103.     } while (0)
  104.  
  105. #define MIN(x,y)    ((x)<(y) ? (x) : (y))
  106. #define MAX(x,y)    ((x)>=(y) ? (x) : (y))
  107.  
  108. /* find_cell() returns a pointer to a cell at 'row', 'col'.  If there is no
  109.    cell currently allocated there, it returns 0. */
  110.  
  111. CELL *
  112. find_cell FUN2(CELLREF, row, CELLREF, col)
  113. {
  114.     ROW *row_ptr;
  115.     COL *col_ptr;
  116.  
  117. #ifdef REVERSE
  118.     CELLREF tmp;
  119.  
  120.     tmp=row;
  121.     row=col;
  122.     col=tmp;
  123. #endif
  124. #ifdef TEST
  125.     if(row<MIN_R || row>MAX_R || col<MIN_C || col>MAX_C)
  126.         panic("%u,%u out of range in find_cell",row,col);
  127. #endif
  128.  
  129.     for(row_ptr=the_rows;row_ptr;row_ptr=row_ptr->row_next) {
  130.         if(row_ptr->row_low<=row && row_ptr->row_high>=row)
  131.             break;
  132.         if(row_ptr->row_low>row) {
  133.             row_ptr=0;
  134.             break;
  135.         }
  136.     }
  137.     if(!row_ptr)
  138.         return 0;
  139.  
  140.     for(col_ptr=row_ptr->cols[row-row_ptr->row_low];col_ptr;col_ptr=col_ptr->col_next) {
  141.         if(col_ptr->col_low<=col && col_ptr->col_high>=col)
  142.             break;
  143.         if(col_ptr->col_low>col) {
  144.             col_ptr=0;
  145.             break;
  146.         }
  147.     }
  148.  
  149.     if(!col_ptr)
  150.         return 0;
  151.     return &(col_ptr->cells[col-col_ptr->col_low]);
  152. }
  153.  
  154. /* find_or_make_cell() is like find_cell(), except that if there is no cell
  155.    allocated there, it allocates one.  It should never return zero. */
  156.  
  157. CELL *
  158. find_or_make_cell FUN2(CELLREF, row, CELLREF, col)
  159. {
  160.     ROW *row_ptr;
  161.  
  162.     COL *col_ptr;
  163.     COL **col_prev;
  164. #ifdef REVERSE
  165.     CELLREF tmp;
  166.  
  167.     tmp=row;
  168.     row=col;
  169.     col=tmp;
  170. #endif
  171. #ifdef TEST
  172.     if(row<MIN_R || row>MAX_R || col<MIN_C || col>MAX_C)
  173.         panic("%u,%u out of range in find_or_make_cell",row,col);
  174. #endif
  175.  
  176.     row_ptr=make_row_at(row,the_rows,&the_rows);
  177.  
  178.     /* cdr down the list of cols until we find the one we want */
  179.     col_prev= &(row_ptr->cols[row-row_ptr->row_low]);
  180.     for(col_ptr= *col_prev;col_ptr;col_ptr= *col_prev) {
  181.  
  182.         /* Have we found the right place? */
  183.         if(col_ptr->col_low<=col && col_ptr->col_high>=col)
  184.             break;
  185.  
  186.         if(col_ptr->col_low>col) {
  187.             /* We've cdr'd past the place in the list where
  188.                the column goes */
  189.             if(col_ptr->col_low>col+COL_BUFF+1) {
  190.                 /* There isn't anything nearby. */
  191.                 col_ptr=0;
  192.             } else {
  193.                 int new_low;
  194.                 int old_num_cols;
  195.                 COL *new_col;
  196.  
  197.                 /* Grow the column structure down a bit so
  198.                    that this column will fit in it */
  199.                 new_low=col-COL_BUFF;
  200.                 if(new_low<MIN_C)
  201.                     new_low=MIN_C;
  202.                 old_num_cols=1+col_ptr->col_high-col_ptr->col_low;
  203.  
  204.                 new_col=col_alloc(new_low,
  205.                         col_ptr->col_high,
  206.                         col_ptr->col_next,
  207.  
  208.                         old_num_cols,
  209.                         col_ptr->col_low,
  210.                         &(col_ptr->cells[0]),
  211.  
  212.                         0);
  213.  
  214.                 *col_prev=new_col;
  215.  
  216.                 col_free(col_ptr);
  217.                 col_ptr=new_col;
  218.             }
  219.             break;
  220.         }
  221.         if(col_ptr->col_high+COL_BUFF+1>=col) {
  222.             /* The column doesn't fit in the current
  223.                col structure, but it can be made to by stretching
  224.                or by merging two col structures.
  225.                So do it. */
  226.             if(col_ptr->col_next && col_ptr->col_next->col_low<=col+COL_BUFF+1) {
  227.                 /* This col structure is close enough to the
  228.                    next one that they should just be merged */
  229.                 COL *the_next;
  230.                 COL *new_col;
  231.  
  232.                 the_next=col_ptr->col_next;
  233.                 if(the_next->col_low<=col) {
  234.                     col_ptr=the_next;
  235.                     break;
  236.                 }
  237.  
  238.                 new_col=col_alloc(col_ptr->col_low,
  239.                         the_next->col_high,
  240.                         the_next->col_next,
  241.  
  242.                         1+col_ptr->col_high-col_ptr->col_low,
  243.                         col_ptr->col_low,
  244.                         &(col_ptr->cells[0]),
  245.  
  246.                         1+the_next->col_high-the_next->col_low,
  247.                         the_next->col_low,
  248.                         &(the_next->cells[0]),
  249.  
  250.                         0);
  251.  
  252.                 *col_prev=new_col;
  253.  
  254.                 col_free(col_ptr);
  255.                 col_free(the_next);
  256.                 col_ptr=new_col;
  257.             } else {
  258.                 int new_high;
  259.                 COL *new_col;
  260.  
  261.                 /* Stretch the col structure a little */
  262.                 if(col>MAX_C-COL_BUFF)
  263.                     new_high=MAX_C;
  264.                 else
  265.                     new_high=col+COL_BUFF;
  266.  
  267.                 new_col=col_alloc(col_ptr->col_low,
  268.                         new_high,
  269.                         col_ptr->col_next,
  270.  
  271.                         1+col_ptr->col_high-col_ptr->col_low,
  272.                         col_ptr->col_low,
  273.                         &(col_ptr->cells[0]),
  274.  
  275.                         0);
  276.  
  277.                 *col_prev=new_col;
  278.  
  279.                 col_free(col_ptr);
  280.                 col_ptr=new_col;
  281.             }
  282.             break;
  283.         }
  284.         col_prev= &(col_ptr->col_next);
  285.     }
  286.     if(!col_ptr) {
  287.         /* We couldn't find any columns.  Create some */
  288.  
  289.         if(col<MIN_C+COL_BUFF)
  290.             col_ptr=col_alloc(MIN_C,
  291.                     col+COL_BUFF,
  292.                     *col_prev,
  293.  
  294.                     0);
  295.         else if(col>MAX_C-COL_BUFF)
  296.             col_ptr=col_alloc(col-COL_BUFF,
  297.                     MAX_C,
  298.                     *col_prev,
  299.  
  300.                     0);
  301.         else
  302.             col_ptr=col_alloc(col-COL_BUFF,
  303.                     col+COL_BUFF,
  304.                     *col_prev,
  305.  
  306.                     0);
  307.         *col_prev= col_ptr;
  308.     }
  309.  
  310.     return &(col_ptr->cells[col-col_ptr->col_low]);
  311. }
  312.  
  313. /* These two return the maximum row/column allocated at the given column/row
  314.    Because of the way the sparse array works, one of them will return the
  315.    same value for all possible inputs.
  316.  */
  317.    
  318. CELLREF
  319. #ifdef REVERSE
  320. max_col FUN1(CELLREF, row)
  321. #else
  322. max_row FUN1(CELLREF, col)
  323. #endif
  324. {
  325.     ROW *rr;
  326.  
  327.     if(!the_rows)
  328.         return MIN_R;
  329.     for(rr=the_rows;rr->row_next;rr=rr->row_next)
  330.         ;
  331.     return rr->row_high;
  332. }
  333.  
  334. CELLREF
  335. #ifdef REVERSE
  336. max_row FUN1(CELLREF, row)
  337. #else
  338. max_col FUN1(CELLREF, row)
  339. #endif
  340. {
  341.     ROW *rr;
  342.     COL *cc;
  343.  
  344.     if(!the_rows)
  345.         return MIN_C;
  346.     for(rr=the_rows;rr;rr=rr->row_next)
  347.         if(rr->row_low<=row && rr->row_high>=row)
  348.             break;
  349.     if(!rr)
  350.         return MIN_C;
  351.     for(cc=rr->cols[row-rr->row_low];cc && cc->col_next;cc=cc->col_next)
  352.         ;
  353.     if(!cc)
  354.         return MIN_C;
  355.     return cc->col_high;
  356. }
  357.  
  358. /* These two return the highest row/column allocated anywhere in the
  359.    spreadsheet.  One of them is easy to find, but the other requires scanning
  360.    the entire sparse array
  361.  */
  362. CELLREF
  363. #ifdef REVERSE
  364. highest_col FUN0()
  365. #else
  366. highest_row FUN0()
  367. #endif
  368. {
  369.     ROW *rr;
  370.  
  371.     if(!the_rows)
  372.         return MIN_R;
  373.     for(rr=the_rows;rr->row_next;rr=rr->row_next)
  374.         ;
  375.     return rr->row_high;
  376. }
  377.  
  378. CELLREF
  379. #ifdef REVERSE
  380. highest_row FUN0()
  381. #else
  382. highest_col FUN0()
  383. #endif
  384. {
  385.     CELLREF ret;
  386.     int n;
  387.     ROW *rr;
  388.     COL *cc;
  389.  
  390.     if(!the_rows)
  391.         return MIN_C;
  392.     ret=MIN_C;
  393.     for(rr=the_rows;rr;rr=rr->row_next) {
  394.         for(n=0;n<rr->row_high-rr->row_low;n++) {
  395.             for(cc=rr->cols[n];cc && cc->col_next;cc=cc->col_next)
  396.                 ;
  397.             if(cc && cc->col_high>ret)
  398.                 ret=cc->col_high;
  399.         }
  400.     }
  401.     return ret;
  402. }
  403.  
  404. /* This is a complicated function.  It takes four or more args.
  405.    The first three are
  406.    The lowest row value we should create
  407.    The highest row value we should create
  408.    the next row structure in the list
  409.    and groups of
  410.      how many col ptrs are in this group (N_IN)
  411.      what row value this group starts at (ROW_IN)
  412.      and a pointer to an array of struct col *s (COL_IN)
  413.    The groups end with a (partial) group whose N_IN is zero
  414.  */
  415.  
  416. static ROW *
  417. row_alloc FUN3N(CELLREF,r_low,CELLREF,r_high,ROW *,r_next)
  418. {
  419.     ROW *ret;
  420.     int    num_rows;
  421.     int    our_row;
  422.     COL **colp;
  423.     int    n_in;
  424.     int    row_in;
  425.     COL **col_in;
  426.     va_list args;
  427.  
  428. #ifdef TEST
  429.     if(r_next && r_next->row_low==r_high+1)
  430.         error_msg("Warning: Consecutive rows allocated");
  431. #endif
  432.     out_of_date();
  433.     num_rows=1+r_high-r_low;
  434.     ret=(ROW *)ck_malloc(sizeof(ROW)+(num_rows-1)*sizeof(ROW *));
  435.     ret->row_low=r_low;
  436.     ret->row_high=r_high;
  437.     ret->row_next=r_next;
  438.  
  439. /*  printf("row_alloc(%d,%d,%d,",r_low,r_high,r_next); */
  440.     var_start(args,r_next);
  441.     our_row=r_low;
  442.     colp= &(ret->cols[0]);
  443.     while(n_in=va_arg(args,int)) {
  444.         row_in=va_arg(args,/* CELLREF */ int);
  445.         while(our_row<row_in) {
  446.             our_row++;
  447.             *colp++=0;
  448.         }
  449.         col_in=(COL **)va_arg(args,COL **);
  450. /*  printf(" %d,%d,%d,",n_in,row_in,col_in); */
  451.         while(n_in--) {
  452.             our_row++;
  453.             *colp++ = *col_in++;
  454.         }
  455.     }
  456.     while(our_row++<=r_high)
  457.         *colp++=0;
  458. /*  printf("0)\n"); */
  459.     va_end(args);
  460.  
  461.     return ret;
  462. }
  463.  
  464. /* This is like row_alloc(), but it allocates columns instead */
  465. static COL *
  466. col_alloc FUN3N(CELLREF,c_low,CELLREF,c_high,COL *,c_next)
  467. {
  468.     COL *ret;
  469.     int    num_cols;
  470.     int    our_col;
  471.     CELL    *cellp;
  472.     int    n_in;
  473.     int    col_in;
  474.     CELL    *cell_in;
  475.     va_list args;
  476.  
  477. #ifdef TEST
  478.     if(c_next && c_next->col_low==c_high+1)
  479.         error_msg("Warning: Consecutive cols allocated");
  480. #endif
  481.     out_of_date();
  482.     num_cols=1+c_high-c_low;
  483.     ret=(COL *)ck_malloc(sizeof(COL)+(num_cols-1)*sizeof(CELL));
  484.     ret->col_low=c_low;
  485.     ret->col_high=c_high;
  486.     ret->col_next=c_next;
  487.  
  488. /*  printf("col_alloc(%d,%d,%d,",c_low,c_high,c_next); */
  489.     var_start(args,c_next);
  490.     our_col=c_low;
  491.     cellp= &(ret->cells[0]);
  492.     while(n_in=va_arg(args,int)) {
  493.         col_in=va_arg(args,/* CELLREF */ int);
  494.         while(our_col<col_in) {
  495.             our_col++;
  496.             /* cellp->cell_string=0; */
  497.             cellp->cell_refs_from=0;
  498.             cellp->cell_refs_to=0;
  499.             cellp->cell_cycle=0;
  500.             cellp->cell_formula=0;
  501.             cellp++->cell_flags=0;
  502.         }
  503.         cell_in=(CELL *)va_arg(args,CELL *);
  504. /*  printf(" %d,%d,%d,",n_in,col_in,cell_in); */
  505.         bcopy(cell_in,cellp,n_in*sizeof(CELL));
  506.         our_col+=n_in;
  507.         cellp+=n_in;
  508.     }
  509.  
  510. /*  printf(" 0)\n"); */
  511.     while(our_col++<=c_high) {
  512.         /* cellp->cell_string=0; */
  513.         cellp->cell_refs_from=0;
  514.         cellp->cell_refs_to=0;
  515.         cellp->cell_cycle=0;
  516.         cellp->cell_formula=0;
  517.         cellp++->cell_flags=0;
  518.     }
  519.  
  520.     return ret;
  521. }
  522.  
  523. /* This function returns a pointer to a row structure that has a row defined
  524.    at ROW.  PREVP points to a row structure somewhere before ROW.  PREVPP
  525.    points to the place where the pointer to PREVP is stored (for use if
  526.    we have to realloc(PREVP,...) */
  527. static ROW *
  528. make_row_at FUN3(CELLREF,row,ROW *,prevp,ROW **,prevpp)
  529. {
  530.     ROW *postp;
  531.     ROW *new_row;
  532.     CELLREF rowhi,rowlo;
  533.  
  534.     while(prevp && prevp->row_next && prevp->row_next->row_low < row) {
  535.         prevpp = &(prevp->row_next);
  536.         prevp=prevp->row_next;
  537.     }
  538.  
  539.     if(prevp && prevp->row_low<=row && prevp->row_high>=row)
  540.         return prevp;
  541.  
  542.     rowhi= (row>MAX_R-ROW_BUFF) ? MAX_R : row+ROW_BUFF;
  543.     rowlo= (row<MIN_R+ROW_BUFF) ? MIN_R : row-ROW_BUFF;
  544.  
  545.     if(   !prevp
  546.         || (    prevp->row_high < rowlo-1
  547.            && (!prevp->row_next || prevp->row_next->row_low-1>rowhi))) {
  548.  
  549.         /* There's no row structure there.  Therefore, create one */
  550.         new_row=row_alloc(rowlo,
  551.                 rowhi,
  552.                 prevp ? prevp->row_next : *prevpp,
  553.  
  554.                 0);
  555.         if(prevp)
  556.             prevp->row_next=new_row;
  557.         else
  558.             *prevpp=new_row;
  559.         return new_row;
  560.     }
  561.  
  562.     if(prevp->row_high+1>=rowlo) {
  563.         if(prevp->row_next && prevp->row_next->row_low-1<=rowhi) {
  564.             /* This row is (nearly) midway between two row
  565.                structures.  Merge them */
  566.             postp=prevp->row_next;
  567.             new_row=row_alloc(prevp->row_low,
  568.                     postp->row_high,
  569.                     postp->row_next,
  570.  
  571.                     1+prevp->row_high-prevp->row_low,
  572.                     prevp->row_low,
  573.                     &(prevp->cols[0]),
  574.  
  575.                     1+postp->row_high-postp->row_low,
  576.                     postp->row_low,
  577.                     &(postp->cols[0]),
  578.  
  579.                     0);
  580.  
  581.             *prevpp=new_row;
  582.  
  583.             row_free(prevp);
  584.             row_free(postp);
  585.             return new_row;
  586.         } else if(prevp->row_low>rowlo) {
  587.             /* The first row struct must be stretched up a bit */
  588.             new_row=row_alloc(rowlo,prevp->row_high,prevp->row_next,
  589.                     1+prevp->row_high-prevp->row_low,
  590.                     prevp->row_low,
  591.                     &(prevp->cols[0]),
  592.  
  593.                     0);
  594.             *prevpp=new_row;
  595.             row_free(prevp);
  596.             return new_row;
  597.         } else {
  598.             /* This row is just past the end of a row
  599.                structure.  Stretch the structure a bit so
  600.                that it'll fit */
  601.             new_row=row_alloc(prevp->row_low,
  602.                     rowhi,
  603.                     prevp->row_next,
  604.  
  605.                     1+prevp->row_high-prevp->row_low,
  606.                     prevp->row_low,
  607.                     &(prevp->cols[0]),
  608.  
  609.                     0);
  610.  
  611.             *prevpp=new_row;
  612.  
  613.             row_free(prevp);
  614.             return new_row;
  615.         }
  616.     }
  617.  
  618.     if(prevp->row_next && prevp->row_next->row_low-1<=rowhi) {
  619.         /* Grow the old row_structure down just a
  620.            little so that this one will fit in it */
  621.         prevpp= &(prevp->row_next);
  622.         postp=prevp->row_next;
  623.  
  624.         new_row=row_alloc(rowlo,
  625.                 postp->row_high,
  626.                 postp->row_next,
  627.  
  628.                 1+postp->row_high-postp->row_low,
  629.                 postp->row_low,
  630.                 &(postp->cols[0]),
  631.  
  632.                 0);
  633.  
  634.         *prevpp=new_row;
  635.  
  636.         row_free(postp);
  637.         return new_row;
  638.     }
  639. #ifdef TEST
  640.     if(prevp->row_low<row || prevp->row_high>row)
  641.         panic("Make row at: %u not in %u %u",row,prevp->row_low,prevp->row_high);
  642. #endif
  643.     return prevp;
  644. }
  645.  
  646.  
  647. /* The next group of routines deal with finding groups of cells in the
  648.    spreadsheet.  They should be smart enough to deal with the spreadsheet
  649.    changing under them.  */
  650. struct find {
  651.     CELLREF lr,lc,hr,hc;
  652.     CELLREF cr,cc;
  653.     int flags;
  654.  
  655.     ROW *nowrow;
  656.     COL **colpptr;
  657.     COL *nowcol;
  658.     int colsleft;
  659.     CELL *nowcell;
  660.     int cellsleft;
  661.     struct find *next;
  662. };
  663. static struct find *f;
  664. static struct obstack find_stack;
  665.  
  666. void
  667. init_cells FUN0()
  668. {
  669.     obstack_begin(&find_stack,sizeof(struct find)*15);
  670. }
  671.  
  672. /* This sets things up so that the next gzillion calls to next_cell_in_range()
  673.    will return one of the cells in the region delineated by RNG.  If
  674.    This will skip over any gaps in the region, but will return zeroed cells
  675.    in the region.  If there are no cells in the region, the first call to
  676.    next_cell_in_range() will return 0
  677.  */
  678. void
  679. find_cells_in_range FUN1(struct rng *,rng)
  680. {
  681.     struct find *oldf;
  682. #ifdef REVERSE
  683. #define    LR    rng->lc
  684. #define LC    rng->lr
  685. #define HR    rng->hc
  686. #define HC    rng->hr
  687. #else
  688. #define LR    rng->lr
  689. #define LC    rng->lc
  690. #define HR    rng->hr
  691. #define HC    rng->hc
  692. #endif
  693. #ifdef TEST
  694.     if(   LR<MIN_R || LR>MAX_R || HR<MIN_R || HR>MAX_R
  695.        || LC<MIN_C || LC>MAX_C || HC<MIN_C || HC>MAX_C)
  696.         panic("find_cells_in_range(%u:%u %u:%u) out of range",LR,HR,LC,HC);
  697. #endif
  698.  
  699.     oldf=f;
  700.     f=obstack_alloc(&find_stack,sizeof(struct find));
  701.     bzero(f,sizeof(struct find));
  702.     f->next=oldf;
  703.     f->lr=LR;
  704.     f->hr=HR;
  705.     f->lc=LC;
  706.     f->hc=HC;
  707.     for(f->nowrow=the_rows;f->nowrow;f->nowrow=f->nowrow->row_next)
  708.         if(f->nowrow->row_high>=f->lr)
  709.             break;
  710.     while(f->nowrow && f->nowrow->row_low<=f->hr) {
  711.         f->cr=f->lr<=f->nowrow->row_low ? f->nowrow->row_low : f->lr;
  712.         f->colpptr= &(f->nowrow->cols[f->cr-f->nowrow->row_low]);
  713.         f->colsleft=1+MIN(f->hr,f->nowrow->row_high)-f->cr;
  714.         while(f->colsleft) {
  715.             --(f->colsleft);
  716.             f->nowcol= *(f->colpptr)++;
  717.             while(f->nowcol && f->nowcol->col_high<f->lc)
  718.                 f->nowcol=f->nowcol->col_next;
  719.             if(f->nowcol && f->nowcol->col_low<=f->hc) {
  720.                 /* Found something */
  721.                 f->cc=(f->lc<f->nowcol->col_low) ? f->nowcol->col_low : f->lc;
  722.                 f->nowcell= &(f->nowcol->cells[f->cc-f->nowcol->col_low]);
  723.                 f->cellsleft=1+MIN(f->hc,f->nowcol->col_high)-f->cc;
  724.                 --(f->cc);
  725. #ifdef TEST
  726.                 if(f->cellsleft<1)
  727.                     panic("Cellsleft %d<1",f->cellsleft);
  728. #endif
  729.                 f->flags=0;
  730.                 return;
  731.             }
  732.             (f->cr)++;
  733.         }
  734.         f->nowrow=f->nowrow->row_next;
  735.     }
  736.     /* If we get here, we searched through the entire range, and didn't
  737.        find *any* cells.  We lose */
  738.     f->flags=1;
  739. }
  740.  
  741. /* This is like find_cells_in_range, except that if the cells don't exist,
  742.    it makes them! */
  743. void
  744. make_cells_in_range FUN1(struct rng *,rng)
  745. {
  746.     ROW **prevpp;
  747.     ROW *myrow;
  748.     int n;
  749.     COL **colpp;
  750.     COL *mycol;
  751.     struct find *oldf;
  752.     CELLREF lr,hr,lc,hc;
  753.  
  754. #ifdef TEST
  755.     if(   LR<MIN_R || LR>MAX_R || HR<MIN_R || HR>MAX_R
  756.        || LC<MIN_C || LC>MAX_C || HC<MIN_C || HC>MAX_C)
  757.         panic("make_cells_in_range(%u:%u %u:%u) out of range",LR,HR,LC,HC);
  758. #endif
  759.     oldf=f;
  760.     f=obstack_alloc(&find_stack,sizeof(struct find));
  761.     bzero(f,sizeof(struct find));
  762.     f->next=oldf;
  763.     f->lr=LR;
  764.     f->lc=LC;
  765.     f->hr=HR;
  766.     f->hc=HC;
  767.  
  768.     f->colsleft=f->hr-f->lr;
  769.     f->cr=f->lr;
  770.     f->cellsleft=1+f->hc-f->lc;
  771.     f->cc=f->lc-1;
  772.  
  773.     lr= f->lr<=MIN_R+ROW_BUFF ? MIN_R : f->lr-ROW_BUFF;
  774.     hr= f->hr>=MAX_R-ROW_BUFF ? MAX_R : f->hr+ROW_BUFF;
  775.  
  776.     if(!the_rows) {
  777.         myrow=the_rows=row_alloc(lr,hr,0,0);
  778.     } else {
  779.         myrow=the_rows;
  780.         prevpp= &the_rows;
  781.         while(myrow && myrow->row_high<lr-1) {
  782.             prevpp= &(myrow->row_next);
  783.             myrow=myrow->row_next;
  784.         }
  785.         if(!myrow || myrow->row_low-1>hr)
  786.             myrow= *prevpp=row_alloc(lr,hr,myrow,0);
  787.         else if(myrow->row_high<hr) {
  788.             ROW *t1,*t2;
  789.  
  790.             while(myrow->row_high<hr && myrow->row_next && myrow->row_next->row_low<=hr+1) {
  791.                 t1=myrow;
  792.                 t2=myrow->row_next;
  793.                 myrow= *prevpp=row_alloc(t1->row_low,t2->row_high,t2->row_next,
  794.                             1+t1->row_high-t1->row_low,t1->row_low,&(t1->cols[0]),
  795.                             1+t2->row_high-t2->row_low,t2->row_low,&(t2->cols[0]),
  796.                             0);
  797.                 row_free(t1);
  798.                 row_free(t2);
  799.             }
  800.             if(myrow->row_high<hr) {
  801.                 t1=myrow;
  802.                 myrow= *prevpp=row_alloc(t1->row_low,hr,t1->row_next,
  803.                             1+t1->row_high-t1->row_low,t1->row_low,&(t1->cols[0]),
  804.                             0);
  805.                 row_free(t1);
  806.             }
  807.         } else if(myrow->row_low>lr) {
  808.             ROW *t1;
  809.  
  810.             t1=myrow;
  811.             myrow= *prevpp=row_alloc(lr,t1->row_high,t1->row_next,
  812.                         1+t1->row_high-t1->row_low,t1->row_low,&(t1->cols[0]),
  813.                         0);
  814.             row_free(t1);
  815.         }
  816.     }
  817. #ifdef TEST
  818.     if(myrow->row_low>f->lr || myrow->row_high<f->hr)
  819.         panic("Myrow isn't big enough");
  820. #endif
  821.     lc= f->lc<=MIN_C+COL_BUFF ? MIN_C : f->lc-COL_BUFF;
  822.     hc= f->hc>=MAX_C-COL_BUFF ? MAX_C : f->hc+COL_BUFF;
  823.  
  824.     for(n=lr-myrow->row_low;n<=hr-myrow->row_low;n++) {
  825.  
  826.         colpp= &(myrow->cols[n]);
  827.         if(!*colpp) {
  828.             *colpp=col_alloc(lc,hc,0,0);
  829.         } else {
  830.             for(mycol= *colpp;mycol;colpp= &(mycol->col_next),mycol= *colpp)
  831.                 if(mycol->col_high+1>=lc)
  832.                     break;
  833.             if(!mycol || mycol->col_low>hc+1)
  834.                 *colpp=col_alloc(lc,hc,mycol,0);
  835.             else if(mycol->col_low<=lc && mycol->col_high>=hc)
  836.                 ;    /* Easy */
  837.             else /* if(mycol->col_low>lc && mycol->col_high>hc) {
  838.                 COL *t1;
  839.  
  840.                 t1=mycol;
  841.                 mycol= *colpp=col_alloc(lc,t1->col_high,t1->col_next,
  842.                             1+t1->col_high-t1->col_low,t1->col_low,&(t1->cells[0]),
  843.                             0);
  844.                 col_free(t1);
  845.             } else */ {
  846.                 COL *t1,*t2;
  847.  
  848.                 while(mycol->col_high<=hc+1
  849.                        && mycol->col_next
  850.                        && mycol->col_next->col_low<=hc+1) {
  851.                     t1=mycol;
  852.                     t2=mycol->col_next;
  853.                     mycol= *colpp=col_alloc(MIN(lc,t1->col_low),t2->col_high,t2->col_next,
  854.                                 1+t1->col_high-t1->col_low,t1->col_low,&(t1->cells[0]),
  855.                                 1+t2->col_high-t2->col_low,t2->col_low,&(t2->cells[0]),
  856.                                 0);
  857.                     col_free(t1);
  858.                     col_free(t2);
  859.                 }
  860.                 if(mycol->col_low>lc || mycol->col_high<hc) {
  861.                     t1=mycol;
  862.                     mycol= *colpp=col_alloc(MIN(lc,t1->col_low),MAX(hc,mycol->col_high),t1->col_next,
  863.                                 1+t1->col_high-t1->col_low,t1->col_low,&(t1->cells[0]),
  864.                                 0);
  865.                     col_free(t1);
  866.                 }
  867.             }
  868.         }
  869.     }
  870.     f->nowrow=myrow;
  871.     f->colpptr= &(f->nowrow->cols[f->lr-f->nowrow->row_low]);
  872.     f->nowcol= *(f->colpptr)++;
  873.     while(f->nowcol->col_high<f->lc)
  874.         f->nowcol=f->nowcol->col_next;
  875.     f->nowcell= &(f->nowcol->cells[f->lc-f->nowcol->col_low]);
  876.  
  877. #ifdef TEST
  878.     if(f->cellsleft<1)
  879.         panic("Cellsleft %d<1",f->cellsleft);
  880. #endif
  881.     f->flags=0;
  882. }
  883.  
  884. /* Return the next cell in the range previously selected by
  885.    find_cells_in_range() or make_cells_in_range()  If row_alloc(),
  886.    row_free(), col_alloc(), or col_free() has been called, re-sync to the
  887.    current state of the spreadsheet. */
  888.  
  889. CELL *
  890. next_cell_in_range FUN0()
  891. {
  892.     struct find *oldf;
  893.  
  894. #ifdef TEST
  895.     if(!f)
  896.         panic("No 'f' in next_cells_in_range!");
  897. #endif
  898.     if(f->flags) {
  899.         if(f->flags&1) {
  900.  done:
  901.             oldf=f->next;
  902.             (void)obstack_free(&find_stack,f);
  903.             f=oldf;
  904.             return 0;
  905.         }
  906.         f->flags=0;
  907.         if(f->cr==f->hr && f->cc==f->hc)
  908.             goto done;
  909.         if(f->cc==f->hc) {    /* JF was f->cc=f->hc */
  910.             f->cc=f->lc-1;
  911.             (f->cr)++;
  912.         }
  913.         for(f->nowrow=the_rows;f->nowrow;f->nowrow=f->nowrow->row_next)
  914.             if(f->nowrow->row_high>=f->cr)
  915.                 break;
  916.         if(!f->nowrow)
  917.             goto done;
  918.         f->colpptr= &(f->nowrow->cols[f->cr-f->nowrow->row_low]);
  919.         f->colsleft= 1+MIN(f->hr,f->nowrow->row_high)-f->cr;
  920.         if(f->colsleft) {
  921.             --(f->colsleft);
  922.             f->nowcol= *(f->colpptr)++;
  923.             while(f->nowcol && f->nowcol->col_high<f->cc)
  924.                 f->nowcol=f->nowcol->col_next;
  925.             if(f->nowcol && f->nowcol->col_low<=f->cc) {
  926.                 (f->cc)++;
  927.                 f->nowcell= &(f->nowcol->cells[f->cc-f->nowcol->col_low]);
  928.                 f->cellsleft=1+MIN(f->hc,f->nowcol->col_high)-f->cc;
  929.                 --(f->cc);
  930.             }
  931.         }
  932.     }
  933.  
  934.     if(f->cellsleft) {
  935. #ifdef TEST
  936.         if(f->cellsleft<1)
  937.             panic("Cellsleft %d<1",f->cellsleft);
  938. #endif
  939.         --(f->cellsleft);
  940.         (f->cc)++;
  941.         return (f->nowcell)++;
  942.     }
  943.  
  944.     /* There are no more cells in the current COL structure.  If there
  945.        might be cells in the next one, try there */
  946.     if(f->nowcol->col_high<f->hc) {
  947.         f->nowcol=f->nowcol->col_next;
  948.         if(f->nowcol && f->nowcol->col_low<=f->hc) {
  949.             f->nowcell= &(f->nowcol->cells[0]);
  950.             f->cellsleft=MIN(f->hc,f->nowcol->col_high)-f->nowcol->col_low;
  951.             f->cc=f->nowcol->col_low;
  952. #ifdef TEST
  953.             if(f->cellsleft<0)
  954.                 panic("Cellsleft %d<1",f->cellsleft);
  955. #endif
  956.             return (f->nowcell)++;
  957.         }
  958.     }
  959.  try_cols:
  960.     /* See if there are any more COLS in the current row structure
  961.        If there are, scan through them for useful cells.  */
  962.     while(f->colsleft) {
  963.         --(f->colsleft);
  964.         (f->cr)++;
  965.         f->nowcol= *(f->colpptr)++;
  966.         while(f->nowcol && f->nowcol->col_high<f->lc)
  967.             f->nowcol=f->nowcol->col_next;
  968.         if(f->nowcol && f->nowcol->col_low<=f->hc) {    /* Found something */
  969.             f->cc=f->lc<f->nowcol->col_low ? f->nowcol->col_low : f->lc;
  970.             f->nowcell= &(f->nowcol->cells[f->cc-f->nowcol->col_low]);
  971.             f->cellsleft=MIN(f->hc,f->nowcol->col_high)-f->cc;
  972. #ifdef TEST
  973.             if(f->cellsleft<0)
  974.                 panic("Cellsleft %d<1",f->cellsleft);
  975. #endif
  976.             return (f->nowcell)++;
  977.         }
  978.     }
  979.  
  980.     /* Have we run out of rows? */
  981.     if(f->nowrow->row_high>=f->hr)
  982.         goto done;
  983.  
  984.     /* Check in the next ROW structure.  There's nothing in this one */
  985.     f->nowrow=f->nowrow->row_next;
  986.     if(!f->nowrow || f->nowrow->row_low>f->hr)
  987.         goto done;
  988.  
  989.     f->colpptr= &(f->nowrow->cols[0]);
  990.     f->colsleft= 1 + MIN(f->hr,f->nowrow->row_high)-f->nowrow->row_low;
  991.     f->cr=f->nowrow->row_low-1;
  992.     goto try_cols;
  993. }
  994.  
  995. /* This is a wrapper to next_cell_in_range that also returns (through
  996.    PUTROW and PUTCOL information about where the cell actually *is*
  997.  */
  998. CELL *
  999. next_row_col_in_range FUN2(CELLREF *,putrow, CELLREF *,putcol)
  1000. {
  1001.     CELL *nxt;
  1002.  
  1003.     nxt=next_cell_in_range();
  1004.     if(nxt) {
  1005. #ifdef REVERSE
  1006.         *putcol=f->cr;
  1007.         *putrow=f->cc;
  1008. #else
  1009.         *putrow=f->cr;
  1010.         *putcol=f->cc;
  1011. #endif
  1012.     } else {
  1013.         *putrow=MIN_R-1;
  1014.         *putcol=MIN_C-1;
  1015.     }
  1016.     return nxt;
  1017. }
  1018.  
  1019. /* This should be called if a function called {find,make}_cells_in_range()
  1020.    and wants to stop calling next_{cell,row_col}_in_range() before they
  1021.    encounter the end of the range */
  1022. void
  1023. no_more_cells FUN0()
  1024. {
  1025.     struct find *oldf;
  1026.  
  1027.     oldf=f->next;
  1028.     (void)obstack_free(&find_stack,f);
  1029.     f=oldf;
  1030. }
  1031.  
  1032. /* This is called by row_alloc and col_alloc to tell
  1033.    next_{cell,row_col}_in_range() that some part of the spreadsheet has
  1034.    changed.
  1035.  */
  1036. static void
  1037. out_of_date FUN0()
  1038. {
  1039.     struct find *tmpf;
  1040.  
  1041.     for(tmpf=f;tmpf;tmpf=tmpf->next)
  1042.         tmpf->flags|=2;
  1043. }
  1044.  
  1045. /* this is your basic trash-the-world function. */
  1046. void
  1047. flush_everything FUN0()
  1048. {
  1049.     ROW *rp,*rnxt;
  1050.     COL *cp,*cnxt;
  1051.     CELL *sp;
  1052.  
  1053.     int nrn;
  1054. #ifndef SPLIT_REFS
  1055.     extern void flush_refs();
  1056. #endif
  1057.  
  1058.     for(rp= the_rows;rp;rp=rnxt) {
  1059.         rnxt=rp->row_next;
  1060.         for(nrn=rp->row_low;nrn<=rp->row_high;nrn++) {
  1061.             for(cp= rp->cols[nrn-rp->row_low];cp;cp= cnxt) {
  1062.                 cnxt=cp->col_next;
  1063.                 for(sp= &(cp->cells[0]);sp<=&(cp->cells[cp->col_high-cp->col_low]);sp++) {
  1064. #ifdef SPLIT_REFS
  1065.                     if(sp->cell_refs_from)
  1066.                         free(sp->cell_refs_from);
  1067.                     if(sp->cell_refs_to)
  1068.                         free(sp->cell_refs_to);
  1069. #endif
  1070.                     if(sp->cell_formula)
  1071.                         byte_free(sp->cell_formula);
  1072.                     if(GET_TYP(sp)==TYP_STR)
  1073.                         free(sp->cell_str);
  1074.                 }
  1075.                 free(cp);
  1076.             }
  1077.         }
  1078.         free(rp);
  1079.         the_rows=0;
  1080.     }
  1081.     flush_variables();
  1082. #ifndef SPLIT_REFS
  1083.     flush_refs();
  1084. #endif
  1085. }
  1086.  
  1087. #ifdef TEST
  1088. extern char *bname[];
  1089. extern char *dbg_print_formula();
  1090. extern char *dbg_print_ref_fm();
  1091. extern char *dbg_print_ref_to();
  1092.  
  1093. extern char print_buf[];
  1094.  
  1095. extern char *bname[];
  1096.  
  1097. void dbg_print_cell();
  1098.  
  1099. /* These debugging functions store useful text about the sparse array
  1100.    in the buffer pointed to by BUF.  If it isn't big enough, you lose. */
  1101.  
  1102. void
  1103. dbg_print_rows FUN0()
  1104. {
  1105.     ROW *row_ptr;
  1106.     CELLREF n,maxx;
  1107.     char *buf;
  1108.  
  1109.     for(row_ptr=the_rows;row_ptr;row_ptr=row_ptr->row_next) {
  1110.         text_line("Row %p:  next %p, low %u, high %u",
  1111.             row_ptr,row_ptr->row_next,row_ptr->row_low,
  1112.             row_ptr->row_high);
  1113.         maxx=row_ptr->row_high-row_ptr->row_low;
  1114.         for(buf=print_buf,n=0;n<=maxx;n++) {
  1115.             (void)sprintf(buf," %p",row_ptr->cols[n]);
  1116.             if(n%8==7) {
  1117.                 text_line(print_buf);
  1118.                 buf=print_buf;
  1119.             } else
  1120.                 buf+=strlen(buf);
  1121.         }
  1122.         if(n%8)
  1123.             text_line(print_buf);
  1124.     }
  1125. }
  1126.  
  1127. void
  1128. dbg_print_cols FUN1(CELLREF, row)
  1129. {
  1130.     ROW *row_ptr;
  1131.     COL *col_ptr;
  1132.     CELLREF maxc,nc;
  1133.     CELL *cp;
  1134.     char *buf;
  1135.  
  1136.     for(row_ptr=the_rows;row_ptr;row_ptr=row_ptr->row_next)
  1137.         if(row_ptr->row_low<=row && row_ptr->row_high>=row)
  1138.             break;
  1139.     if(!row_ptr)
  1140.         return;
  1141.  
  1142.     for(col_ptr=row_ptr->cols[row-row_ptr->row_low];col_ptr;col_ptr=col_ptr->col_next) {
  1143.         text_line("Col %p:  Next %p, low %u, high %u",
  1144.             col_ptr,col_ptr->col_next,col_ptr->col_low,
  1145.             col_ptr->col_high);
  1146.         maxc=col_ptr->col_high-col_ptr->col_low;
  1147.  
  1148.         for(cp= &(col_ptr->cells[0]),buf=print_buf,nc=0;nc<=maxc;nc++,cp++) {
  1149.             switch(GET_TYP(cp)) {
  1150.             case 0:
  1151.                 (void)strcpy(buf,"         .");
  1152.                 break;
  1153.             case TYP_FLT:
  1154.                 (void)sprintf(buf," %8gf",cp->cell_flt);
  1155.                 break;
  1156.             case TYP_INT:
  1157.                 (void)sprintf(buf," %8ldi",cp->cell_int);
  1158.                 break;
  1159.             case TYP_ERR:
  1160.                 (void)sprintf(buf," %8.8se",ename[cp->cell_err]);
  1161.                 break;
  1162.             case TYP_BOL:
  1163.                 (void)sprintf(buf," %8sb",bname[cp->cell_bol]);
  1164.                 break;
  1165.             case TYP_STR:
  1166.                 (void)sprintf(buf," %8.8ss",cp->cell_str);
  1167.                 break;
  1168.             default:
  1169.                 (void)sprintf(buf," %8dU",GET_TYP(cp));
  1170.                 break;
  1171.             }
  1172.             if(nc%8==7) {
  1173.                 text_line(print_buf);
  1174.                 buf=print_buf;
  1175.             } else
  1176.                 buf+=strlen(buf);
  1177.         }
  1178.         if(nc%8)
  1179.             text_line(print_buf);
  1180.     }
  1181. }
  1182.  
  1183. void
  1184. dbg_print_array FUN0()
  1185. {
  1186.     int maxx;
  1187.     int nr;
  1188.     int maxc;
  1189.     int nc;
  1190.     COL *col_ptr;
  1191.     CELL *cp;
  1192.     ROW * row_ptr;
  1193.     char *buf;
  1194.  
  1195.     for(row_ptr=the_rows;row_ptr;row_ptr=row_ptr->row_next) {
  1196.         text_line("Row %p:  next %p, low %u, high %u",
  1197.             row_ptr,row_ptr->row_next,row_ptr->row_low,
  1198.             row_ptr->row_high);
  1199.         maxx=row_ptr->row_high-row_ptr->row_low;
  1200.         for(nr=0,buf=print_buf;nr<=maxx;nr++) {
  1201.             (void)sprintf(buf," %p",row_ptr->cols[nr]);
  1202.             if(nr%8==7) {
  1203.                 text_line(print_buf);
  1204.                 buf=print_buf;
  1205.             } else
  1206.                 buf+=strlen(buf);
  1207.         }
  1208.         if(nr%8)
  1209.             text_line(print_buf);
  1210.  
  1211.         for(nr=0;nr<=maxx;nr++) {
  1212.             for(col_ptr=row_ptr->cols[nr];col_ptr;col_ptr=col_ptr->col_next) {
  1213.                 text_line("Col %p:  Next %p, low %u, high %u",
  1214.                     col_ptr,col_ptr->col_next,col_ptr->col_low,
  1215.                     col_ptr->col_high);
  1216.                 maxc=col_ptr->col_high-col_ptr->col_low;
  1217.  
  1218.                 for(cp= &(col_ptr->cells[0]),buf=print_buf,nc=0;nc<=maxc;nc++,cp++) {
  1219.                     (void)sprintf(buf," %p",cp);
  1220.                     if(nc%8==7) {
  1221.                         text_line(print_buf);
  1222.                         buf=print_buf;
  1223.                     } else
  1224.                         buf+=strlen(buf);
  1225.                 }
  1226.                 if(nc%8)
  1227.                     text_line(print_buf);
  1228.  
  1229.                 for(cp= &(col_ptr->cells[0]),nc=0;nc<=maxc;nc++,cp++)
  1230.                     dbg_print_cell(cp);
  1231.             }
  1232.         }
  1233.     }
  1234. }
  1235.  
  1236. void
  1237. dbg_print_cell FUN1(CELL *,cp)
  1238. {
  1239.     char *ptr1,*ptr2;
  1240.     char tmpbuf[30];
  1241.  
  1242.     switch(GET_TYP(cp)) {
  1243.     case 0:
  1244.         ptr1="(null)";
  1245.         ptr2="";
  1246.         break;
  1247.     case TYP_FLT:
  1248.         sprintf(tmpbuf,"Float: %.16g",cp->cell_flt);
  1249.         ptr1=tmpbuf;
  1250.         ptr2="";
  1251.         break;
  1252.     case TYP_INT:
  1253.         sprintf(tmpbuf,"Int: %ld",cp->cell_int);
  1254.         ptr1=tmpbuf;
  1255.         ptr2="";
  1256.         break;
  1257.     case TYP_ERR:
  1258.         sprintf(tmpbuf,"Error: %d: ",cp->cell_err);
  1259.         ptr1=tmpbuf;
  1260.         ptr2=ename[cp->cell_err];
  1261.         break;
  1262.     case TYP_BOL:
  1263.         sprintf(tmpbuf,"Bool: %d: ",cp->cell_bol);
  1264.         ptr1=tmpbuf;
  1265.         ptr2=bname[cp->cell_bol];
  1266.         break;
  1267.     case TYP_STR:
  1268.         sprintf(tmpbuf,"String: %p: ",cp->cell_str);
  1269.         ptr1=tmpbuf;
  1270.         ptr2=cp->cell_str;
  1271.         break;
  1272.     default:
  1273.         sprintf(tmpbuf,"Unknown: %d",GET_TYP(cp));
  1274.         ptr1=tmpbuf;
  1275.         ptr2="";
  1276.         break;
  1277.     }
  1278.     text_line("Cell %p: flags %#lx, cycle %u, formula %p, value %s%s",
  1279.         cp,cp->cell_flags,cp->cell_cycle,cp->cell_formula,
  1280.         ptr1,ptr2);
  1281.     dbg_print_formula(cp->cell_formula);
  1282.     dbg_print_ref_fm(cp->cell_refs_from);
  1283.     dbg_print_ref_to(cp->cell_refs_to);
  1284. }
  1285.  
  1286. #endif
  1287.